package com.njzxw.fs.createJava;

import com.njzxw.fs.commonutil.util.StringHelper;
import com.njzxw.fs.createJava.repository.CreateTableReq;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 根据表单生成java代码
 */
@Service
public class CreateTableJava {

    @Value("${my.create_table_java.table}")
    private String[] table;

    @Value("${my.create_table_java.javaPackage}")
    private String javaPackage;

    @Value("${my.create_table_java.targetPath}")
    private String targetPath;

    @Value("${my.create_table_java.split}")
    private String split;

    @Value("${my.create_table_java.htmlModule}")
    private String htmlModule = "";

    @Autowired
    private CreateTableReq createTableReq;

    public org.slf4j.Logger logger = LoggerFactory.getLogger(this.getClass());

    @Value("${my.create_table_java.templateDirectory}")
    private String templateDirectory;

    private String app = "";

//    public void test(){
//        List<Map<String,Object>> list = createTableReq.getTest();
//        int touru = 10;
//        int xiazhu = 0;//0小1单
//        for(int i=0;i<list.size();i++){
//            Map<String,Object> map = list.get(i);
//            String xiao = StringHelper.get(map,"小");
//            String qihao = StringHelper.get(map,"期号");
//            String dan = StringHelper.get(map,"单");
//            String shuying = "";
//
//            if(xiazhu == 0 && !"".equals(xiao)){
//                shuying = touru+"";
//            }else if(xiazhu == 0 && "".equals(xiao)){
//                shuying = (0-touru)+"";
//                xiazhu = 1;
//            }else if(xiazhu == 1 && !"".equals(dan)){
//                shuying = touru+"";
//            }else if(xiazhu == 1 && "".equals(dan)){
//                shuying = (0-touru)+"";
//                xiazhu = 0;
//            }
//
//            createTableReq.updateTest(touru+"",shuying,qihao);
//        }
//
//    }

    @PostConstruct
    public void execute(){
//        test();
        logger.info("===========开始生成文件===========================start");
        app = StringUtils.capitalize(javaPackage.substring(javaPackage.lastIndexOf("\\.")+1));

        if(!StringUtils.isBlank(split)){
            javaPackage += "."+split;
//            targetPath += "/"+split;
        }

        //单表操作
        List<Map<String,Object>> tables = createTableReq.tables(java.util.Arrays.asList(table));

        if(tables != null && !tables.isEmpty()){
            for(Map<String,Object> map:tables){
                String tableName = StringHelper.get(map,"TABLE_NAME");
                String tableComment = StringHelper.get(map,"TABLE_COMMENT");
                List<Map<String,Object>> columnList = createTableReq.showColumn(tableName);

                //生成javaBean
                Map<String, Object> beanMap = createBean(tableName,columnList);
                String path = targetPath+"/java/";
                if(!StringUtils.isBlank(split)){
                    path += split;
                }
                create(templateDirectory,"bean.java",path+"/bean",StringHelper.get(beanMap,"className")+"Bean.java",beanMap);

                //生成数据库操作Repository
                path = targetPath+"/java/";
                if(!StringUtils.isBlank(split)){
                    path += split;
                }
                Map<String, Object> repositoryMap = createRepositoryMap(tableName,columnList);
                create(templateDirectory,"repository.java",path+"/repository",StringHelper.get(beanMap,"className")+"Repository.java",repositoryMap);

                //生成server文件
                path = targetPath+"/java/";
                if(!StringUtils.isBlank(split)){
                    path += split;
                }
                Map<String, Object> serverMap = createServerMap(tableName,columnList);
                create(templateDirectory,"server.java",path+"/server",StringHelper.get(beanMap,"className")+"Server.java",serverMap);

                //生成action文件
                path = targetPath+"/java/";
                if(!StringUtils.isBlank(split)){
                    path += split;
                }
                Map<String, Object> controllerMap = createControllerMap(tableName,columnList);
                create(templateDirectory,"controller.java",path+"/controller",StringHelper.get(beanMap,"className")+"Controller.java",controllerMap);

                //生成test文件
                path = targetPath+"/test/";
                Map<String, Object> testMap = createTestMap(tableName,columnList);
                testMap.put("tableComment",tableComment);
                create(templateDirectory,"test.java",path+(javaPackage.replaceAll("\\.","/"))+"/controller",StringHelper.get(beanMap,"className")+"ControllerTest.java",testMap);

                //生成html文件
                path = targetPath+"/html/";
                Map<String, Object> indexMap = createIndexMap(tableName,columnList);
                create(templateDirectory,"index.html",path+(StringHelper.get(indexMap,"className_")),"index.html",indexMap);
                create(templateDirectory,"add.html",path+(StringHelper.get(indexMap,"className_")),"add.html",indexMap);

            }
        }
        logger.info("===========结束生成文件===========================end");
        System.exit(0);

    }

    public Map<String,Object> createIndexMap(String tableName,List<Map<String,Object>> columnList){
        Map<String, Object> map = new HashMap<>();
        String className = underline2Camel(tableName.replace("t_",""),false);
        map.put("className", StringUtils.capitalize(className));
        map.put("className_", StringUtils.uncapitalize(className));
        map.put("DclassName_", className.toUpperCase());
        map.put("package",javaPackage);
        map.put("posts","${maven.url.post}");
        map.put("model",javaPackage.substring(javaPackage.lastIndexOf("\\.")+1));
        map.put("app",app);
        map.put("colimnList",createTableReq.showColumn(tableName));

        if(!StringUtils.isBlank(htmlModule)){
            map.put("dirs","../..");
            map.put("path",htmlModule+"/"+StringUtils.uncapitalize(className));
        }else{
            map.put("dirs","..");
            map.put("path",StringUtils.uncapitalize(className));
        }

        return map;
    }

    public Map<String,Object> createTestMap(String tableName,List<Map<String,Object>> columnList){
        Map<String, Object> map = new HashMap<>();
        String className = underline2Camel(tableName.replace("t_",""),false);
        map.put("className", StringUtils.capitalize(className));
        map.put("className_", StringUtils.uncapitalize(className));
        map.put("package",javaPackage);
        map.put("app",app);
        map.put("colimnList",createTableReq.showColumn(tableName));
        return map;
    }

    public Map<String,Object> createControllerMap(String tableName,List<Map<String,Object>> columnList){
        Map<String, Object> map = new HashMap<>();
        String className = underline2Camel(tableName.replace("t_",""),false);
        map.put("className", StringUtils.capitalize(className));
        map.put("className_", StringUtils.uncapitalize(className));
        map.put("package",javaPackage);
        return map;
    }

    public Map<String,Object> createServerMap(String tableName,List<Map<String,Object>> columnList){
        Map<String, Object> map = new HashMap<>();
        String className = underline2Camel(tableName.replace("t_",""),false);
        map.put("className", StringUtils.capitalize(className));
        map.put("className_", StringUtils.uncapitalize(className));
        map.put("package",javaPackage);
        return map;
    }

    /**
     *
     * @param tableName
     * @param columnList
     * @return
     */
    public Map<String, Object> createRepositoryMap(String tableName,List<Map<String,Object>> columnList){
        Map<String, Object> map = new HashMap<>();
        String className = underline2Camel(tableName.replace("t_",""),false);
        map.put("className", StringUtils.capitalize(className));
        map.put("className_", StringUtils.uncapitalize(className));
        map.put("package",javaPackage);

        List<Map<String,Object>> columns = createTableReq.showColumn(tableName);

        //生成对应的sql语句
        String queryPageSql = "select e.name oper_name,"+getQueryColumn(columns,true,"a.")+" from "+
                tableName+" a left join t_manager_user e on a.oper_id = e.id where 1=1 and "+getWhereColumn(columns,"a.");
        map.put("queryPageSql",queryPageSql);

        String queryIdSql = "select e.name oper_name,"+getQueryColumn(columns,true,"a.")+" from "+
                tableName+" a left join t_manager_user e on a.oper_id = e.id where a.id = #{id}";
        map.put("queryIdSql",queryIdSql);

        String updateSql = "update "+tableName+" a (#{"+StringUtils.uncapitalize(className)+"Bean}) where  a.id = #{id}";
        map.put("updateSql",updateSql);

        String deleteSql = "delete a from "+tableName+" a where  a.id in (#{ids})";
        map.put("deleteSql",deleteSql);

        String insertSql = "insert into "+tableName+"(#{"+StringUtils.uncapitalize(className)+"Bean})";
        map.put("insertSql",insertSql);
        return map;
    }

    private String getWhereColumn(List<Map<String,Object>> columns,String qz){

        String sql = "";

        for(Map<String,Object> map :columns){
            String column_name = StringHelper.get(map,"COLUMN_NAME");
            String data_type = StringHelper.get(map,"DATA_TYPE");
            if(column_name.contains("time")||column_name.contains("date")){
                sql += " and DATE_FORMAT("+qz+column_name+",'%Y-%m-%d %T') >= #{min_"+column_name+"}";
                sql += " and DATE_FORMAT("+qz+column_name+",'%Y-%m-%d %T') <= #{max_"+column_name+"}";
            }else{
                if("Integer".equals(data_type)){
                    if(!column_name.equals("oper_id")&&!column_name.equals("update_oper")){
                        sql += " and "+qz+column_name+" = #{"+column_name+"}";
                    }
                }else{
                    if(!column_name.equals("oper_id")&&!column_name.equals("update_oper_id")) {
                        sql += " and " + qz + column_name + " like #{" + column_name + "}";
                    }
                }

            }
        }

        return sql.substring(5);

    }

    /**
     *
     * @param columns
     * @param isExeDate 是否处理date 如果true 就会在date咧咧上加上date_format
     * @param qz 前缀 a.
     * @return
     */
    private String getQueryColumn(List<Map<String,Object>> columns,boolean isExeDate,String qz){
        StringBuffer sql = new StringBuffer();
        sql.append(qz+"id,");

        for(Map<String,Object> map :columns){
            String column_name = StringHelper.get(map,"COLUMN_NAME");

            if(column_name.contains("time")||column_name.contains("date")){
                if(isExeDate){
                    sql.append("DATE_FORMAT("+qz+column_name+",'%Y-%m-%d %T') "+column_name+",") ;
                }else{
                    sql.append(qz+column_name+",");
                }
            }else{
                sql.append(qz+column_name+",");
            }
        }
//        logger.debug("sqlsqlsqlslq:"+sql+columns);
        return sql.substring(0,sql.length()-1);
    }

    /**
     * 生成bean需要的参数信息
     *
     * @param tableName
     * @param columnList
     * @return
     */
    public Map<String, Object> createBean(String tableName,List<Map<String,Object>> columnList){
        Map<String, Object> map = new HashMap<>();
        String className = underline2Camel(tableName.replace("t_",""),false);
        map.put("className", className);
        map.put("package",javaPackage);
        map.put("colimnList",createTableReq.showColumn(tableName));
        return map;
    }

    /**
     *
     * @param templateDirectory 模板目录  src/main/resources/template
     * @param templateFile 模板名称
     * @param targetPath 模板生成后存放目录
     * @param fileName 模板生成后新文件名
     * @param map
     */
    public void create(String templateDirectory,String templateFile,String targetPath,String fileName,Map<String, Object> map){

        // 生成目标文件
        Writer writer = null;
        try {
            // 创建文件夹
            String root = this.getClass().getResource("/").toURI().getPath().replace("/classes/","");

            String dir = root+targetPath;

            File dirs = new File(dir);
            if(!dirs.exists()){
                dirs.mkdirs();
            }

            logger.debug("targetPath:"+dir);

            File nFile = new File(dir+"/"+fileName);
            if (nFile.exists()) {
                nFile.delete();
            }

            writer = new FileWriter(nFile);
            Template template = getConfiguration(templateDirectory).getTemplate(templateFile, "UTF-8");
            template.process(map, writer);
        } catch (Exception e) {
            logger.error("生成模板失败",e);
        } finally {
            try {
                writer.close();
            } catch (IOException e) {
                logger.error("生成模板失败",e);
            }
        }

    }

    private boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            //递归删除目录中的子目录下
            for (int i=0; i<children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        // 目录此时为空，可以删除
        return dir.delete();
    }

    private Configuration getConfiguration(String templateDirectory) throws URISyntaxException {

        Configuration configuration = new Configuration(Configuration.VERSION_2_3_22);
        try {
            configuration.setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX);

            configuration.setDirectoryForTemplateLoading(new File(this.getClass().getResource("/").toURI().getPath()+templateDirectory));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return configuration;
    }


    private Pattern humpPattern = Pattern.compile("[A-Z]");

    /**
     * 驼峰转下划线,效率比上面高
     *
     * @param str
     * @return
     */
    public String humpToLine2(String str){
        Matcher matcher = humpPattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while(matcher.find()){
            matcher.appendReplacement(sb, "_"+matcher.group(0).toLowerCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    /**
     * 下划线转驼峰
     *
     * @param line 源字符串
     * @param smallCamel 大小驼峰,是否为小驼峰
     * @return
     */
    public String underline2Camel(String line,boolean smallCamel){
        if(line==null||"".equals(line)){
            return "";
        }
        StringBuffer sb=new StringBuffer();
        Pattern pattern=Pattern.compile("([A-Za-z\\d]+)(_)?");
        Matcher matcher=pattern.matcher(line);
        while(matcher.find()){
            String word=matcher.group();
            sb.append(smallCamel&&matcher.start()==0?Character.toLowerCase(word.charAt(0)):Character.toUpperCase(word.charAt(0)));
            int index=word.lastIndexOf('_');
            if(index>0){
                sb.append(word.substring(1, index).toLowerCase());
            }else{
                sb.append(word.substring(1).toLowerCase());
            }
        }
        return sb.toString();
    }

}
